/**
 * iWeb2GooglePages - Converts export iWeb content and uploads it to GPs.
 * Copyright (C) 2008 Will Droste
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 */
package org.iweb2gps;

import static javax.swing.SwingConstants.LEFT;
import static org.jdesktop.application.Application.getInstance;
import static org.jdesktop.layout.GroupLayout.BASELINE;
import static org.jdesktop.layout.GroupLayout.DEFAULT_SIZE;
import static org.jdesktop.layout.GroupLayout.LEADING;
import static org.jdesktop.layout.GroupLayout.PREFERRED_SIZE;
import static org.jdesktop.layout.LayoutStyle.RELATED;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.text.MessageFormat;

import javax.swing.ActionMap;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTextArea;
import javax.swing.Timer;

import net.miginfocom.layout.CC;
import net.miginfocom.layout.LC;
import net.miginfocom.swing.MigLayout;

import org.jdesktop.application.Action;
import org.jdesktop.application.ApplicationContext;
import org.jdesktop.application.FrameView;
import org.jdesktop.application.ResourceMap;
import org.jdesktop.application.SingleFrameApplication;
import org.jdesktop.application.Task;
import org.jdesktop.application.TaskMonitor;
import org.jdesktop.layout.GroupLayout;

import com.apple.eawt.ApplicationAdapter;
import com.apple.eawt.ApplicationEvent;

/**
 * The application's main frame.
 */
public class View extends FrameView {

    /**
     * 
     */
    public View(final SingleFrameApplication app) {
        super(app);

        // initialize all the components
        initComponents();

        // add the about/preference range..
        com.apple.eawt.Application apple = com.apple.eawt.Application
                .getApplication();
        apple.addApplicationListener(new ApplicationAdapter() {
            /**
             * Show the {@link AboutBox}.
             * 
             * @see com.apple.eawt.ApplicationListener#handleAbout(com.apple.eawt.ApplicationEvent)
             */
            @Override
            public void handleAbout(ApplicationEvent evt) {
                super.handleAbout(evt);
                if (aboutBox == null) {
                    JFrame mainFrame = App.getApplication().getMainFrame();
                    aboutBox = new AboutBox(mainFrame);
                    aboutBox.setLocationRelativeTo(mainFrame);
                }
                App.getApplication().show(aboutBox);
                evt.setHandled(true);
            }

            /**
             * Make sure to call the shutdown method..
             * 
             * @see com.apple.eawt.ApplicationAdapter#handleQuit(com.apple.eawt.ApplicationEvent)
             */
            @Override
            public void handleQuit(ApplicationEvent evt) {
                super.handleQuit(evt);
                evt.setHandled(true);
                app.exit();
            }

            /**
             * Open the preferences dialog to setup.
             * 
             * @see com.apple.eawt.ApplicationListener#handlePreferences(com.apple.eawt.ApplicationEvent)
             */
            @Override
            public void handlePreferences(ApplicationEvent evt) {
                super.handleAbout(evt);
                if (preferenceBox == null) {
                    JFrame mainFrame = App.getApplication().getMainFrame();
                    preferenceBox = new PreferencesBox(mainFrame);
                    preferenceBox.setLocationRelativeTo(mainFrame);
                }
                App.getApplication().show(preferenceBox);
                evt.setHandled(true);
            }
        });
        apple.setEnabledPreferencesMenu(true);
        apple.addPreferencesMenuItem();

        // status bar initialization - message timeout, idle icon and busy
        // animation, etc
        ResourceMap resourceMap = getResourceMap();
        int messageTimeout = resourceMap.getInteger("StatusBar.messageTimeout");
        messageTimer = new Timer(messageTimeout, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                statusMessageLabel.setText("");
            }
        });
        messageTimer.setRepeats(false);
        int busyAnimationRate = resourceMap
                .getInteger("StatusBar.busyAnimationRate");
        String templ = "StatusBar.busyIcons[{0}]";
        for (int i = 0; i < busyIcons.length; i++) {
            final String tmp = MessageFormat.format(templ, i);
            busyIcons[i] = resourceMap.getIcon(tmp);
        }
        busyIconTimer = new Timer(busyAnimationRate, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                busyIconIndex = (busyIconIndex + 1) % busyIcons.length;
                statusAnimationLabel.setIcon(busyIcons[busyIconIndex]);
            }
        });
        idleIcon = resourceMap.getIcon("StatusBar.idleIcon");
        statusAnimationLabel.setIcon(idleIcon);

        // connecting action tasks to status bar via TaskMonitor
        TaskMonitor taskMonitor = new TaskMonitor(getApplication().getContext());
        taskMonitor.addPropertyChangeListener(new AppPropertyChangeListener());
    }

    /**
     * Handle property events that change the status and progress bar.
     */
    class AppPropertyChangeListener implements PropertyChangeListener {
        public void propertyChange(PropertyChangeEvent evt) {
            String propertyName = evt.getPropertyName();
            if ("started".equals(propertyName)) {
                if (!busyIconTimer.isRunning()) {
                    statusAnimationLabel.setIcon(busyIcons[0]);
                    busyIconIndex = 0;
                    busyIconTimer.start();
                }
                progressBar.setVisible(true);
                progressBar.setIndeterminate(true);
            } else if ("done".equals(propertyName)) {
                busyIconTimer.stop();
                statusAnimationLabel.setIcon(idleIcon);
                progressBar.setVisible(false);
                progressBar.setValue(0);
            } else if ("message".equals(propertyName)) {
                String text = (String) (evt.getNewValue());
                statusMessageLabel.setText((text == null) ? "" : text);
                messageTimer.restart();
                // add this to the status panel..
                statusArea.append(text + "\n");
                // scroll to the bottom..
                int height = statusArea.getHeight()
                        - statusArea.getVisibleRect().height;
                scrollPanel.getVerticalScrollBar().setValue(height);
            } else if ("progress".equals(propertyName)) {
                int value = (Integer) (evt.getNewValue());
                progressBar.setVisible(true);
                progressBar.setIndeterminate(false);
                progressBar.setValue(value);
            }
        }
    }

    /**
     * Apple Application Adapter to handle Preferences and About..
     */
    class AppleAppListener extends ApplicationAdapter {
        public AppleAppListener() {
            super();
        }
        /**
         * Show the {@link AboutBox}.
         * 
         * @see com.apple.eawt.ApplicationListener#handleAbout(com.apple.eawt.ApplicationEvent)
         */
        @Override
        public void handleAbout(ApplicationEvent evt) {
            super.handleAbout(evt);
            if (aboutBox == null) {
                JFrame mainFrame = App.getApplication().getMainFrame();
                aboutBox = new AboutBox(mainFrame);
                aboutBox.setLocationRelativeTo(mainFrame);
            }
            App.getApplication().show(aboutBox);
            evt.setHandled(true);
        }

        @Override
        public void handleQuit(ApplicationEvent evt) {
            super.handleQuit(evt);
            evt.setHandled(true);

        }

        /**
         * Open the preferences dialog to setup.
         * 
         * @see com.apple.eawt.ApplicationListener#handlePreferences(com.apple.eawt.ApplicationEvent)
         */
        @Override
        public void handlePreferences(ApplicationEvent evt) {
            super.handleAbout(evt);
            if (preferenceBox == null) {
                JFrame mainFrame = App.getApplication().getMainFrame();
                preferenceBox = new PreferencesBox(mainFrame);
                preferenceBox.setLocationRelativeTo(mainFrame);
            }
            App.getApplication().show(preferenceBox);
            evt.setHandled(true);
        }
    }

    /**
     * Initializes the main panel (inner panel)..
     */
    private void initMainPanel() {
        // get the application context..
        ApplicationContext ctx = getInstance(App.class).getContext();
        ResourceMap resourceMap = ctx.getResourceMap(View.class);

        // create the main container for configuration..
        mainPanel = new JPanel();
        mainPanel.setName("mainPanel");
        LC lc = new LC().fill();
        mainPanel.setLayout(new MigLayout(lc));

        // status page separator..
        mainPanel.add(new JLabel(resourceMap.getString("googlepages.text")),
                "wrap");

        // add debug text panel..
        statusArea = new JTextArea();
        statusArea.setName("statusArea");
        statusArea.setEditable(false);
        scrollPanel = new JScrollPane(statusArea);
        mainPanel.add(scrollPanel, new CC().spanX().grow().wrap());

        // add start button..
        startButton = new JButton();
        startButton.setText(resourceMap.getString("startButton.text"));
        startButton.setName("startButton");
        ActionMap map = ctx.getActionMap(getClass(), this);
        javax.swing.Action act = (javax.swing.Action) map.get("startButton");
        startButton.setAction(act);
        mainPanel.add(startButton, "right, span");
    }

    /**
     * Create the status panel and lay it out..
     */
    private void initStatusPanel() {
        statusPanel = new JPanel();
        statusPanel.setName("statusPanel");

        JSeparator statusPanelSeparator = new JSeparator();
        statusPanelSeparator.setName("statusPanelSeparator");

        statusMessageLabel = new JLabel();
        statusMessageLabel.setName("statusMessageLabel");

        statusAnimationLabel = new JLabel();
        statusAnimationLabel.setHorizontalAlignment(LEFT);
        statusAnimationLabel.setName("statusAnimationLabel");

        progressBar = new JProgressBar();
        progressBar.setName("progressBar");
        progressBar.setVisible(false);
        GroupLayout statusPanelLayout = new GroupLayout(statusPanel);
        statusPanel.setLayout(statusPanelLayout);
        statusPanelLayout.setHorizontalGroup(
            statusPanelLayout.createParallelGroup(LEADING)
            .add(statusPanelSeparator, DEFAULT_SIZE, 400, Short.MAX_VALUE)
            .add(statusPanelLayout.createSequentialGroup()
                .addContainerGap()
                .add(statusMessageLabel)
                .addPreferredGap(RELATED, 226, Short.MAX_VALUE)
                .add(progressBar, PREFERRED_SIZE, DEFAULT_SIZE, PREFERRED_SIZE)
                .addPreferredGap(RELATED)
                .add(statusAnimationLabel)
                .addContainerGap())
        );
        statusPanelLayout.setVerticalGroup(
            statusPanelLayout.createParallelGroup(LEADING)
            .add(statusPanelLayout.createSequentialGroup()
                .add(statusPanelSeparator, PREFERRED_SIZE, 2, PREFERRED_SIZE)
                .addPreferredGap(RELATED, DEFAULT_SIZE, Short.MAX_VALUE)
                .add(statusPanelLayout.createParallelGroup(BASELINE)
                    .add(statusMessageLabel)
                    .add(statusAnimationLabel)
                    .add(progressBar, PREFERRED_SIZE, DEFAULT_SIZE, PREFERRED_SIZE))
                .add(3, 3, 3))
        );
    }

    private void initComponents() {
        initMainPanel();
        initStatusPanel();
        setComponent(mainPanel);
        setStatusBar(statusPanel);
    }

    /**
     * Start to convert and upload the files..
     */
    @Action
    public Task startButton() {
        // get the application preferences..
        return new ProcessTask(App.getApplication());
    }

    Runnable bob = new Runnable() {
        public void run() {
            AppPreferences prefs;
            startButton.setEnabled(false);
            startButton.setText("Cancel");
            File dest = new File(System.getProperty("java.io.tmpdir"), "iweb");
            try {
                prefs = new AppPreferences();
                File src = new File(prefs.getExportDirectory());
                // create the directory..
                dest.mkdirs();
                // clear current status..
                statusArea.setText("");
                // convert the files..
                IWebConverter converter = new IWebConverter(src, dest);
                converter.addListener(new IWebConverter.Listener() {
                    public void processing(int idx, int total, File f) {
                        // add each file..
                        statusArea.append(f.toString() + "\n");
                        // scroll to the bottom..
                        int height = statusArea.getHeight()
                                - statusArea.getVisibleRect().height;
                        scrollPanel.getVerticalScrollBar().setValue(height);
                    }
                });
                converter.convert();
                // upload each file in the directory..
                Upload upload = new Upload(prefs.getDomain(), prefs
                        .getUserName(), prefs.getPassword());
                upload.login();
                for (File f : dest.listFiles()) {
                    statusArea.append(f.toString() + "\n");
                    // scroll to the bottom..
                    int height = statusArea.getHeight()
                            - statusArea.getVisibleRect().height;
                    scrollPanel.getVerticalScrollBar().setValue(height);
                }
                upload.logout();
            } catch (Exception e) {
            } finally {
                // clear the directory..
                // try {
                // FileUtils.deleteDirectory(dest);
                // } catch (IOException e) {
                // // TODO Auto-generated catch block
                // e.printStackTrace();
                // }
                startButton.setText("Start");
                startButton.setEnabled(true);
            }
        }
    };

    /*
     * 
     */
    private JPanel mainPanel;
    private JProgressBar progressBar;
    private JButton startButton;
    private JLabel statusAnimationLabel;
    private JLabel statusMessageLabel;
    private JPanel statusPanel;
    private JTextArea statusArea;
    private JScrollPane scrollPanel;

    private final Timer messageTimer;
    private final Timer busyIconTimer;
    private final Icon idleIcon;
    private final Icon[] busyIcons = new Icon[15];
    private int busyIconIndex = 0;

    private JDialog aboutBox;
    private JDialog preferenceBox;
    
    /**
     * Easy abstract class for listener.
     */
    public static class AbstractWindowListner implements WindowListener {

        /* (non-Javadoc)
         * @see java.awt.event.WindowListener#windowActivated(java.awt.event.WindowEvent)
         */
        public void windowActivated(WindowEvent arg0) {
        }

        /* (non-Javadoc)
         * @see java.awt.event.WindowListener#windowClosed(java.awt.event.WindowEvent)
         */
        public void windowClosed(WindowEvent arg0) {
        }

        /* (non-Javadoc)
         * @see java.awt.event.WindowListener#windowClosing(java.awt.event.WindowEvent)
         */
        public void windowClosing(WindowEvent arg0) {
        }

        /* (non-Javadoc)
         * @see java.awt.event.WindowListener#windowDeactivated(java.awt.event.WindowEvent)
         */
        public void windowDeactivated(WindowEvent arg0) {
        }

        /* (non-Javadoc)
         * @see java.awt.event.WindowListener#windowDeiconified(java.awt.event.WindowEvent)
         */
        public void windowDeiconified(WindowEvent arg0) {
        }

        /* (non-Javadoc)
         * @see java.awt.event.WindowListener#windowIconified(java.awt.event.WindowEvent)
         */
        public void windowIconified(WindowEvent arg0) {
        }

        /* (non-Javadoc)
         * @see java.awt.event.WindowListener#windowOpened(java.awt.event.WindowEvent)
         */
        public void windowOpened(WindowEvent arg0) {
        }
    }
}
